package com.example.casserver.service.impl;

import com.example.casserver.model.ServiceTicket;
import com.example.casserver.model.TicketGrantingTicket;
import com.example.casserver.service.TicketService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * CAS票据服务实现类
 * 提供票据的创建、验证、失效和清理功能
 * 使用内存存储方式管理票据，适用于单节点部署
 * 对于集群部署，建议使用分布式缓存（如Redis）存储票据
 */
@Service
public class TicketServiceImpl implements TicketService {

    /**
     * 使用线程安全的ConcurrentHashMap存储票据
     * Key: 票据ID
     * Value: 服务票据对象
     */
    private final Map<String, ServiceTicket> stStore = new ConcurrentHashMap<>();

    /**
     * TGT票据存储
     */
    private final Map<String, TicketGrantingTicket> tgtStore = new ConcurrentHashMap<>();

    /**
     * 生成新的服务票据
     * 票据ID格式为："ST-" + UUID
     *
     * @param username 用户名
     * @param service  目标服务地址
     * @return 新生成的服务票据
     */
    @Override
    public ServiceTicket generateTicket(String username, String service) {
        String ticketId = "ST-" + UUID.randomUUID().toString();
        ServiceTicket ticket = new ServiceTicket(ticketId, username, service);
        stStore.put(ticketId, ticket);
        return ticket;
    }

    /**
     * 验证服务票据
     * 验证成功后票据将被标记为已使用，防止重复使用
     *
     * @param ticketId 票据ID
     * @return 如果票据有效则返回票据对象，否则返回null
     */
    @Override
    public ServiceTicket validateTicket(String ticketId) {
        ServiceTicket ticket = stStore.get(ticketId);
        if (ticket != null && ticket.isValid()) {
            ticket.setUsed(true);
            return ticket;
        }
        stStore.remove(ticketId);
        return null;
    }

    /**
     * 使指定的票据失效
     *
     * @param ticketId 需要失效的票据ID
     */
    @Override
    public void invalidateTicket(String ticketId) {
        stStore.remove(ticketId);
    }

    /**
     * 使指定用户的所有票据失效
     * 通常在用户登出时调用，确保所有服务都能感知到用户的登出操作
     *
     * @param username 用户名
     */
    @Override
    public void invalidateUserTickets(String username) {
        stStore.values().removeIf(ticket -> ticket.getUsername().equals(username));
        tgtStore.values().removeIf(tgt -> tgt.getUsername().equals(username));
    }

    /**
     * 定时清理过期票据
     * 每5分钟执行一次，移除所有过期的票据
     * 防止票据存储过大，影响系统性能
     */
    @Scheduled(fixedRate = 300000) // 5分钟
    public void cleanupExpiredTickets() {
        stStore.values().removeIf(ServiceTicket::isExpired);
        tgtStore.values().removeIf(TicketGrantingTicket::isExpired);
    }

    @Override
    public TicketGrantingTicket createTicketGrantingTicket(String username) {
        TicketGrantingTicket tgt = new TicketGrantingTicket(username);
        tgtStore.put(tgt.getId(), tgt);
        return tgt;
    }

    @Override
    public TicketGrantingTicket getTicketGrantingTicket(String tgtId) {
        TicketGrantingTicket tgt = tgtStore.get(tgtId);
        if (tgt != null && tgt.isValid()) {
            return tgt;
        }
        tgtStore.remove(tgtId);
        return null;
    }

    @Override
    public void invalidateTicketGrantingTicket(String tgtId) {
        tgtStore.remove(tgtId);
    }

    @Override
    public ServiceTicket generateServiceTicket(String tgtId, String service) {
        TicketGrantingTicket tgt = getTicketGrantingTicket(tgtId);
        if (tgt != null) {
            return generateTicket(tgt.getUsername(), service);
        }
        return null;
    }
} 